{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "ax1r8W0rU8d1"
   },
   "source": [
    "# 线性回归 - Linear Regreesion\n",
    "\n",
    "此Notebook是配合Andrew Ng \"Machine Leanring\"中[线性回归](https://github.com/loveunk/machine-learning-deep-learning-notes/blob/master/machine-learning/linear-regression.md)部分学习使用。\n",
    "\n",
    "测试用python版本为3.6\n",
    "* 机器学习路径：https://github.com/loveunk/machine-learning-deep-learning-notes/\n",
    "* 内容正文综合参考网络资源，使用中如果有疑问请联络：www.kaikai.ai"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "kgTnKLvOU8d2"
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "sns.set(context=\"notebook\", style=\"whitegrid\", palette=\"dark\")\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "Nje4hmN0U8d6"
   },
   "outputs": [],
   "source": [
    "df = pd.read_csv('ex1.linear_regreesion.ipynb', names=['population', 'profit']) # 读取数据并赋予列名"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "a9p1GK2iU8d8"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>population</th>\n",
       "      <th>profit</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>{</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>\"cells\": [</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>{</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>\"cell_type\": \"markdown\"</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>\"metadata\": {</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                   population profit\n",
       "0                           {    NaN\n",
       "1                  \"cells\": [    NaN\n",
       "2                           {    NaN\n",
       "3     \"cell_type\": \"markdown\"    NaN\n",
       "4               \"metadata\": {    NaN"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.head() # 显示数据前五行"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "Ly0Fs3unU8eA"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "RangeIndex: 1273 entries, 0 to 1272\n",
      "Data columns (total 2 columns):\n",
      "population    1273 non-null object\n",
      "profit        108 non-null object\n",
      "dtypes: object(2)\n",
      "memory usage: 20.0+ KB\n"
     ]
    }
   ],
   "source": [
    "df.info() # 打印df的class信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "WsQ2uPs6muT7"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>population</th>\n",
       "      <th>profit</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>1273</td>\n",
       "      <td>108</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>unique</th>\n",
       "      <td>474</td>\n",
       "      <td>69</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>top</th>\n",
       "      <td>\"\\n\"</td>\n",
       "      <td>X</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>freq</th>\n",
       "      <td>93</td>\n",
       "      <td>12</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       population profit\n",
       "count        1273    108\n",
       "unique        474     69\n",
       "top          \"\\n\"      X\n",
       "freq           93     12"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.describe() # 打印df的统计信息"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "dtj0pJAOU8eE"
   },
   "source": [
    "***\n",
    "# 看下原始数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "ON7EiaK7U8eE",
    "scrolled": true
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'pd' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-2-306dbccc8772>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m      8\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[1;31m# 读取文件，指定列名\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m \u001b[0mdf\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread_csv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'ex1.linear_regreesion.ipynb'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mnames\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'population'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'profit'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     11\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     12\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'pd' is not defined"
     ]
    }
   ],
   "source": [
    "def convert_to_float(value):\n",
    "    try:\n",
    "        return float(value)\n",
    "    except ValueError:\n",
    "        print(f\"Could not convert value {value} to float, replacing with NaN.\")\n",
    "        return float('nan')\n",
    "\n",
    "\n",
    "# 读取文件，指定列名\n",
    "df = pd.read_csv('ex1.linear_regreesion.ipynb', names=['population', 'profit'])\n",
    "\n",
    "\n",
    "# 检查并转换 'population' 和 'profit' 列的数据类型为 float\n",
    "df['population'] = df['population'].apply(convert_to_float)\n",
    "df['profit'] = df['profit'].apply(convert_to_float)\n",
    "\n",
    "\n",
    "# 使用 lmplot 绘制散点图\n",
    "sns.lmplot('population', 'profit', df, size=6, fit_reg=False)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "wRWRxgtAU8eH"
   },
   "outputs": [],
   "source": [
    "def get_X(df): # 读取特征\n",
    "#     \"\"\"\n",
    "#     use concat to add intersect feature to avoid side effect\n",
    "#     not efficient for big dataset though\n",
    "#     \"\"\"\n",
    "    ones = pd.DataFrame({'ones': np.ones(len(df))})#ones是m行1列的dataframe\n",
    "    data = pd.concat([ones, df], axis=1)  # 合并数据，根据列合并\n",
    "    return data.iloc[:, :-1].as_matrix()  # 这个操作返回 ndarray,不是矩阵\n",
    "\n",
    "\n",
    "def get_y(df):#读取标签\n",
    "#     '''assume the last column is the target'''\n",
    "    return np.array(df.iloc[:, -1])#df.iloc[:, -1]是指df的最后一列\n",
    "\n",
    "\n",
    "def normalize_feature(df):\n",
    "#     \"\"\"Applies function along input axis(default 0) of DataFrame.\"\"\"\n",
    "    return df.apply(lambda column: (column - column.mean()) / column.std())#特征缩放"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "GPFqxv_zU8eJ"
   },
   "source": [
    "多变量的假设 h 表示为：${{h}_{\\theta }}\\left( x \\right)={{\\theta }_{0}}+{{\\theta }_{1}}{{x}_{1}}+{{\\theta }_{2}}{{x}_{2}}+...+{{\\theta }_{n}}{{x}_{n}}$。\n",
    "\n",
    "这个公式中有n+1个参数和n个变量，为了使得公式能够简化一些，引入${{x}_{0}}=1$，则公式转化为：  ${{h}_{\\theta }}\\left( x \\right)={{\\theta }_{0}x_0}+{{\\theta }_{1}}{{x}_{1}}+{{\\theta }_{2}}{{x}_{2}}+...+{{\\theta }_{n}}{{x}_{n}}$。\n",
    "\n",
    "此时模型中的参数是一个n+1维的向量，任何一个训练实例也都是n+1维的向量，特征矩阵X的维度是 m*(n+1)。 因此公式可以简化为：${{h}_{\\theta }}\\left( x \\right)={{\\theta }^{T}}X$，其中上标T代表矩阵转置。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "on8_khfsU8eQ"
   },
   "source": [
    "# 计算代价函数\n",
    "$$J\\left( \\theta  \\right)=\\frac{1}{2m}\\sum\\limits_{i=1}^{m}{{{\\left( {{h}_{\\theta }}\\left( {{x}^{(i)}} \\right)-{{y}^{(i)}} \\right)}^{2}}}$$\n",
    "\n",
    "其中：\n",
    "\n",
    "$${{h}_{\\theta }}\\left( x \\right)={{\\theta }^{T}}X={{\\theta }_{0}}{{x}_{0}}+{{\\theta }_{1}}{{x}_{1}}+{{\\theta }_{2}}{{x}_{2}}+...+{{\\theta }_{n}}{{x}_{n}}$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "yomFBPelU8eQ"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1262, 1) <class 'pandas.core.frame.DataFrame'>\n",
      "(1262,) <class 'pandas.core.series.Series'>\n"
     ]
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "\n",
    "# 从文件中读取数据到 DataFrame df 中，假设文件名为 'your_data.csv'\n",
    "df = pd.read_csv('ex1.linear_regreesion.ipynb', names=['population', 'profit'])\n",
    "\n",
    "# 查看数据维度\n",
    "data = df\n",
    "def get_X(data):\n",
    "    # 这里需要根据你的数据结构和需求编写 get_X 函数，以下是一个示例，假设 X 是除了最后一列外的数据\n",
    "    return data.iloc[:, :-1]\n",
    "\n",
    "\n",
    "def get_y(data):\n",
    "    # 这里需要根据你的数据结构和需求编写 get_y 函数，以下是一个示例，假设 y 是最后一列数据\n",
    "    return data.iloc[:, -1]\n",
    "\n",
    "\n",
    "X = get_X(data)\n",
    "print(X.shape, type(X))\n",
    "\n",
    "y = get_y(data)\n",
    "print(y.shape, type(y))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "AeTfJ6UyU8eT"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1353, 1) <class 'pandas.core.frame.DataFrame'>\n",
      "(1353,) <class 'pandas.core.series.Series'>\n",
      "[0.]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "\n",
    "def get_X(data):\n",
    "    # 这里需要根据你的数据结构和需求编写 get_X 函数，以下是一个示例，假设 X 是除了最后一列外的数据\n",
    "    return data.iloc[:, :-1]\n",
    "\n",
    "\n",
    "def get_y(data):\n",
    "    # 这里需要根据你的数据结构和需求编写 get_y 函数，以下是一个示例，假设 y 是最后一列数据\n",
    "    return data.iloc[:, -1]\n",
    "\n",
    "\n",
    "# 从文件中读取数据到 DataFrame df 中，假设文件名为 'your_data.csv'\n",
    "df = pd.read_csv('ex1.linear_regreesion.ipynb', names=['population', 'profit'])\n",
    "data = df\n",
    "\n",
    "X = get_X(data)\n",
    "print(X.shape, type(X))\n",
    "\n",
    "\n",
    "y = get_y(data)\n",
    "print(y.shape, type(y))\n",
    "\n",
    "\n",
    "theta = np.zeros(X.shape[1])  # X.shape[1]=2, 代表特征数 n\n",
    "print(theta)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "ntnGgUoKU8eV"
   },
   "outputs": [],
   "source": [
    "def lr_cost(theta, X, y):\n",
    "    \"\"\" 计算代价函数\n",
    "    X: R(m*n), m 样本数, n 特征数\n",
    "    y: R(m)\n",
    "    theta : R(n), 线性回归的参数\n",
    "    \"\"\"\n",
    "    m = X.shape[0]#m为样本数\n",
    "\n",
    "    inner = X @ theta - y  # R(m*1)，X @ theta等价于X.dot(theta)\n",
    "\n",
    "    # 1*m @ m*1 = 1*1 in matrix multiplication\n",
    "    # but you know numpy didn't do transpose in 1d array, so here is just a\n",
    "    # vector inner product to itselves\n",
    "    square_sum = inner.T @ inner\n",
    "    cost = square_sum / (2 * m)\n",
    "\n",
    "    return cost"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "BPFR1bKOU8eY"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.]\n",
      "nan\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\mhy\\lib\\site-packages\\ipykernel_launcher.py:21: RuntimeWarning: invalid value encountered in double_scalars\n"
     ]
    }
   ],
   "source": [
    "if np.isnan(X).any() or np.isnan(y).any() or np.isinf(X).any() or np.isinf(y).any():\n",
    "    raise ValueError(\"X or y contains NaN or infinity values.\")\n",
    "\n",
    "theta = np.zeros(X.shape[1])  # X.shape[1] 代表特征数 n\n",
    "print(theta)\n",
    "\n",
    "cost = lr_cost(theta, X, y)  # 返回 cost 的值\n",
    "print(cost)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "KZ9oOCHrU8eb"
   },
   "source": [
    "# 批量梯度下降 - Batch Gradient Decent\n",
    "$$\\begin{aligned}{{\\theta }_{j}} &:={{\\theta }_{j}}-\\alpha \\frac{\\partial }{\\partial {{\\theta }_{j}}}J\\left( \\theta  \\right) \\\\ &:= {{\\theta }_{j}}-\\alpha \\frac{1}{m} \\sum^{m}_{i=1}\\left( h_\\theta \\left(x^{(i)}\\right) -y^{(i)}  \\right)x^{(i)}_j \\end{aligned}$$\n",
    "注意：对于所有的$j$，需要同时更新$\\theta_j$。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "4_JZqMY3U8ec"
   },
   "outputs": [],
   "source": [
    "def gradient(theta, X, y):\n",
    "  \"\"\"\n",
    "  计算梯度，也就是 J(θ)的偏导数\n",
    "  \"\"\"\n",
    "  m = X.shape[0]\n",
    "\n",
    "  inner = X.T @ (X @ theta - y)  # (m,n).T @ (m, 1) -> (n, 1)，X @ theta等价于X.dot(theta)\n",
    "\n",
    "  return inner / m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "IRexXn6EU8ee"
   },
   "outputs": [],
   "source": [
    "def batch_gradient_decent(theta, X, y, epoch, alpha=0.01):\n",
    "  \"\"\"\n",
    "  批量梯度下降函数。拟合线性回归，返回参数和代价\n",
    "    epoch: 批处理的轮数\n",
    "  \"\"\"\n",
    "  cost_data = [lr_cost(theta, X, y)]\n",
    "  _theta = theta.copy()  # 拷贝一份，不和原来的theta混淆\n",
    "\n",
    "  for _ in range(epoch):\n",
    "    _theta = _theta - alpha * gradient(_theta, X, y)\n",
    "    cost_data.append(lr_cost(_theta, X, y))\n",
    "\n",
    "  return _theta, cost_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "Lx_dnNrxU8ei"
   },
   "outputs": [
    {
     "ename": "ParserError",
     "evalue": "Error tokenizing data. C error: Expected 1 fields in line 4, saw 2\n",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mParserError\u001b[0m                               Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-12-f8afb61717c2>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m     12\u001b[0m \u001b[1;31m# 从文件中读取数据到 DataFrame df 中，确保文件名和格式正确\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     13\u001b[0m \u001b[1;31m# 假设文件名为 'data.csv'\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 14\u001b[1;33m \u001b[0mdf\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread_csv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'ex1.linear_regreesion.ipynb'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     15\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     16\u001b[0m \u001b[1;31m# 检查并转换数据类型，错误处理为 coerce，将无法转换的数据设为 NaN\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\mhy\\lib\\site-packages\\pandas\\io\\parsers.py\u001b[0m in \u001b[0;36mparser_f\u001b[1;34m(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, squeeze, prefix, mangle_dupe_cols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, dayfirst, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, escapechar, comment, encoding, dialect, tupleize_cols, error_bad_lines, warn_bad_lines, skipfooter, doublequote, delim_whitespace, low_memory, memory_map, float_precision)\u001b[0m\n\u001b[0;32m    676\u001b[0m                     skip_blank_lines=skip_blank_lines)\n\u001b[0;32m    677\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 678\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0m_read\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfilepath_or_buffer\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    679\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    680\u001b[0m     \u001b[0mparser_f\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__name__\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\mhy\\lib\\site-packages\\pandas\\io\\parsers.py\u001b[0m in \u001b[0;36m_read\u001b[1;34m(filepath_or_buffer, kwds)\u001b[0m\n\u001b[0;32m    444\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    445\u001b[0m     \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 446\u001b[1;33m         \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mparser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnrows\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    447\u001b[0m     \u001b[1;32mfinally\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    448\u001b[0m         \u001b[0mparser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mclose\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\mhy\\lib\\site-packages\\pandas\\io\\parsers.py\u001b[0m in \u001b[0;36mread\u001b[1;34m(self, nrows)\u001b[0m\n\u001b[0;32m   1034\u001b[0m                 \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'skipfooter not supported for iteration'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1035\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1036\u001b[1;33m         \u001b[0mret\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_engine\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnrows\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1037\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1038\u001b[0m         \u001b[1;31m# May alter columns / col_dict\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\mhy\\lib\\site-packages\\pandas\\io\\parsers.py\u001b[0m in \u001b[0;36mread\u001b[1;34m(self, nrows)\u001b[0m\n\u001b[0;32m   1846\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mread\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mnrows\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mNone\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1847\u001b[0m         \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1848\u001b[1;33m             \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_reader\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnrows\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1849\u001b[0m         \u001b[1;32mexcept\u001b[0m \u001b[0mStopIteration\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1850\u001b[0m             \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_first_chunk\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mpandas\\_libs\\parsers.pyx\u001b[0m in \u001b[0;36mpandas._libs.parsers.TextReader.read\u001b[1;34m()\u001b[0m\n",
      "\u001b[1;32mpandas\\_libs\\parsers.pyx\u001b[0m in \u001b[0;36mpandas._libs.parsers.TextReader._read_low_memory\u001b[1;34m()\u001b[0m\n",
      "\u001b[1;32mpandas\\_libs\\parsers.pyx\u001b[0m in \u001b[0;36mpandas._libs.parsers.TextReader._read_rows\u001b[1;34m()\u001b[0m\n",
      "\u001b[1;32mpandas\\_libs\\parsers.pyx\u001b[0m in \u001b[0;36mpandas._libs.parsers.TextReader._tokenize_rows\u001b[1;34m()\u001b[0m\n",
      "\u001b[1;32mpandas\\_libs\\parsers.pyx\u001b[0m in \u001b[0;36mpandas._libs.parsers.raise_parser_error\u001b[1;34m()\u001b[0m\n",
      "\u001b[1;31mParserError\u001b[0m: Error tokenizing data. C error: Expected 1 fields in line 4, saw 2\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "def get_X(data):\n",
    "    # 假设 X 是除了最后一列外的数据，并将其转换为 numpy 数组\n",
    "    return data.iloc[:, :-1].values.astype(np.float64)\n",
    "\n",
    "def get_y(data):\n",
    "    # 假设 y 是最后一列数据，并将其转换为 numpy 数组\n",
    "    return data.iloc[:, -1].values.astype(np.float64)\n",
    "\n",
    "# 从文件中读取数据到 DataFrame df 中，确保文件名和格式正确\n",
    "# 假设文件名为 'data.csv'\n",
    "df = pd.read_csv('ex1.linear_regreesion.ipynb')\n",
    "\n",
    "# 检查并转换数据类型，错误处理为 coerce，将无法转换的数据设为 NaN\n",
    "df = df.apply(pd.to_numeric, errors='coerce')\n",
    "\n",
    "# 删除包含 NaN 的行\n",
    "df = df.dropna()\n",
    "\n",
    "data = df\n",
    "\n",
    "X = get_X(data)\n",
    "y = get_y(data)\n",
    "\n",
    "# 初始化 theta，X.shape[1] 代表特征数 n\n",
    "theta = np.zeros(X.shape[1])\n",
    "print(theta)\n",
    "\n",
    "epoch = 500\n",
    "# 确保 batch_gradient_decent 函数正确实现\n",
    "def batch_gradient_decent(theta, X, y, epoch):\n",
    "    alpha = 0.01  # 学习率\n",
    "    m = X.shape[0]\n",
    "    for i in range(epoch):\n",
    "        predictions = np.dot(X, theta)\n",
    "        errors = predictions - y\n",
    "        gradient = np.dot(X.T, errors) / m\n",
    "        theta -= alpha * gradient\n",
    "    return theta\n",
    "\n",
    "final_theta = batch_gradient_decent(theta, X, y, epoch)\n",
    "print(final_theta)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "kCe-db1AU8en"
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "can't multiply sequence by non-int of type 'float'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-5-a2e91e608d1b>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m     25\u001b[0m \u001b[0mepoch\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m1500\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     26\u001b[0m \u001b[1;31m# 计算最终的 theta\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 27\u001b[1;33m \u001b[0mfinal_theta\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mbatch_gradient_decent\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtheta\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mX\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mepoch\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     28\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     29\u001b[0m \u001b[1;31m# 打印最终的 theta\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m<ipython-input-5-a2e91e608d1b>\u001b[0m in \u001b[0;36mbatch_gradient_decent\u001b[1;34m(theta, X, y, epoch, alpha)\u001b[0m\n\u001b[0;32m     14\u001b[0m     \u001b[0mm\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m  \u001b[1;31m# 样本数量\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     15\u001b[0m     \u001b[1;32mfor\u001b[0m \u001b[0m_\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mepoch\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 16\u001b[1;33m         \u001b[0mpredictions\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mX\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtheta\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     17\u001b[0m         \u001b[0merrors\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpredictions\u001b[0m \u001b[1;33m-\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     18\u001b[0m         \u001b[0mgradient\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mX\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mT\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0merrors\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m/\u001b[0m \u001b[0mm\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mTypeError\u001b[0m: can't multiply sequence by non-int of type 'float'"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from sklearn import linear_model\n",
    "\n",
    "# 假设您已经加载了数据并进行了预处理\n",
    "# data = pd.read_csv('your_data.csv')  # 替换为您的数据文件路径\n",
    "\n",
    "# 准备数据\n",
    "X = data.iloc[:, :-1].values  # 特征值\n",
    "y = data.iloc[:, -1].values   # 目标值\n",
    "\n",
    "# 定义批量梯度下降函数\n",
    "def batch_gradient_decent(theta, X, y, epoch, alpha=0.01):\n",
    "    m = len(y)  # 样本数量\n",
    "    for _ in range(epoch):\n",
    "        predictions = X.dot(theta)\n",
    "        errors = predictions - y\n",
    "        gradient = X.T.dot(errors) / m\n",
    "        theta = theta - alpha * gradient\n",
    "    return theta\n",
    "\n",
    "# 初始化 theta\n",
    "theta = np.zeros(X.shape[1])\n",
    "# 设置迭代次数\n",
    "epoch = 1500\n",
    "# 计算最终的 theta\n",
    "final_theta = batch_gradient_decent(theta, X, y, epoch)\n",
    "\n",
    "# 打印最终的 theta\n",
    "print(final_theta)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "yigjBbL4U8eq"
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "\n",
    "# 假设您的数据是这样的\n",
    "data = {\n",
    "    'population': [100, 200, 300, 400, 500],\n",
    "    'profit': [10, 20, 30, 40, 50]\n",
    "}\n",
    "cost_data = pd.DataFrame(data)\n",
    "cost_data\n",
    "# 看下代价数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "ZrMX8THHU8et"
   },
   "outputs": [],
   "source": [
    "from sklearn.linear_model import LinearRegression\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "# 假设您已经有了一个名为 cost_data 的 DataFrame，并且它包含 'population' 和 'profit' 列\n",
    "X = cost_data['population'].values.reshape(-1, 1)  # 特征值\n",
    "y = cost_data['profit'].values  # 目标值\n",
    "\n",
    "# 创建线性回归模型实例\n",
    "lr = LinearRegression()\n",
    "\n",
    "# 训练模型\n",
    "lr.fit(X, y)\n",
    "\n",
    "# 获取最终的参数\n",
    "final_theta = lr.coef_, lr.intercept_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "B9VOLMPqk2Os"
   },
   "source": [
    "scikit-learn model的预测表现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "5gM2jYk2T0Hv",
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from sklearn import linear_model\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import pandas as pd  # 如果您需要从DataFrame中提取数据\n",
    "\n",
    "# 准备数据\n",
    "# 假设您有一个名为 data 的 DataFrame，包含 'population' 和 'profit' 列\n",
    "data = pd.DataFrame({\n",
    "    'population': [100, 200, 300, 400, 500],\n",
    "    'profit': [10, 20, 30, 40, 50]\n",
    "})\n",
    "\n",
    "# 提取特征和目标值\n",
    "X = data['population'].values.reshape(-1, 1)  # 特征值，需要reshape成二维数组\n",
    "y = data['profit'].values  # 目标值\n",
    "\n",
    "# 训练线性回归模型\n",
    "model = linear_model.LinearRegression()\n",
    "model.fit(X, y)\n",
    "\n",
    "# 获取预测值\n",
    "f = model.predict(X).flatten()\n",
    "\n",
    "# 绘制散点图和回归线\n",
    "plt.scatter(X[:, 0], y, label='Training Data')  # 确保 x 和 y 的维度匹配\n",
    "plt.plot(X[:, 0], f, 'r', label='Prediction')\n",
    "plt.legend(loc=2)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "rsQw66Y9U8ew"
   },
   "source": [
    "# 代价数据可视化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "YZyEbK4RU8ew"
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns  # 导入seaborn库，并赋予别名sns\n",
    "\n",
    "# 定义代价数据和迭代轮数\n",
    "cost_data = [0.1, 0.05, 0.01, 0.005, 0.002, 0.001]  # 示例代价数据\n",
    "epoch = len(cost_data)  # 根据代价数据的长度计算轮数\n",
    "\n",
    "# 绘制时间序列图\n",
    "sns.lineplot(x=np.arange(epoch), y=cost_data)\n",
    "plt.xlabel('epoch')\n",
    "plt.ylabel('cost')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "5XhEi6SqU8ez"
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.linear_model import LinearRegression\n",
    "\n",
    "\n",
    "# 假设 data 是您的 DataFrame，包含 'population' 和 'profit' 列\n",
    "data = pd.DataFrame({\n",
    "    'population': [100, 200, 300, 400, 500],\n",
    "    'profit': [10, 20, 30, 40, 50]\n",
    "})\n",
    "\n",
    "\n",
    "# 准备数据\n",
    "X = data['population'].values.reshape(-1, 1)  # 特征值，需要 reshape 成二维数组\n",
    "y = data['profit'].values  # 目标值\n",
    "\n",
    "\n",
    "# 训练线性回归模型\n",
    "model = LinearRegression()\n",
    "model.fit(X, y)\n",
    "\n",
    "\n",
    "# 提取模型参数\n",
    "final_theta = (model.intercept_, model.coef_[0])  # (intercept, slope)\n",
    "\n",
    "\n",
    "# 绘制散点图和回归线\n",
    "b = final_theta[0]  # intercept，Y 轴上的截距\n",
    "m = final_theta[1]  # slope，斜率\n",
    "\n",
    "\n",
    "# 确保 data.population 是一维数组\n",
    "plt.scatter(data['population'], data['profit'], label=\"Training data\")\n",
    "plt.plot(data['population'], data['population'] * m + b, 'r', label=\"Prediction\")\n",
    "plt.legend(loc=2)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "67DO0QyBU8e2"
   },
   "source": [
    "# 3- 选修章节"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "Tb-CO9raU8e2"
   },
   "outputs": [
    {
     "ename": "FileNotFoundError",
     "evalue": "File b'ex1data2.txt' does not exist",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mFileNotFoundError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-2-598bc3574227>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mraw_data\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread_csv\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'ex1data2.txt'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mnames\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'square'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'bedrooms'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'price'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      2\u001b[0m \u001b[0mraw_data\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mhead\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\mhy\\lib\\site-packages\\pandas\\io\\parsers.py\u001b[0m in \u001b[0;36mparser_f\u001b[1;34m(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, squeeze, prefix, mangle_dupe_cols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, dayfirst, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, escapechar, comment, encoding, dialect, tupleize_cols, error_bad_lines, warn_bad_lines, skipfooter, doublequote, delim_whitespace, low_memory, memory_map, float_precision)\u001b[0m\n\u001b[0;32m    676\u001b[0m                     skip_blank_lines=skip_blank_lines)\n\u001b[0;32m    677\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 678\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0m_read\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfilepath_or_buffer\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    679\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    680\u001b[0m     \u001b[0mparser_f\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__name__\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mname\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\mhy\\lib\\site-packages\\pandas\\io\\parsers.py\u001b[0m in \u001b[0;36m_read\u001b[1;34m(filepath_or_buffer, kwds)\u001b[0m\n\u001b[0;32m    438\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    439\u001b[0m     \u001b[1;31m# Create the parser.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 440\u001b[1;33m     \u001b[0mparser\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mTextFileReader\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfilepath_or_buffer\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    441\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    442\u001b[0m     \u001b[1;32mif\u001b[0m \u001b[0mchunksize\u001b[0m \u001b[1;32mor\u001b[0m \u001b[0miterator\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\mhy\\lib\\site-packages\\pandas\\io\\parsers.py\u001b[0m in \u001b[0;36m__init__\u001b[1;34m(self, f, engine, **kwds)\u001b[0m\n\u001b[0;32m    785\u001b[0m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0moptions\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'has_index_names'\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mkwds\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'has_index_names'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    786\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 787\u001b[1;33m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_make_engine\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mengine\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    788\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    789\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mclose\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\mhy\\lib\\site-packages\\pandas\\io\\parsers.py\u001b[0m in \u001b[0;36m_make_engine\u001b[1;34m(self, engine)\u001b[0m\n\u001b[0;32m   1012\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m_make_engine\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mengine\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m'c'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1013\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mengine\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;34m'c'\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1014\u001b[1;33m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_engine\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mCParserWrapper\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mf\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0moptions\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1015\u001b[0m         \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1016\u001b[0m             \u001b[1;32mif\u001b[0m \u001b[0mengine\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;34m'python'\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mD:\\mhy\\lib\\site-packages\\pandas\\io\\parsers.py\u001b[0m in \u001b[0;36m__init__\u001b[1;34m(self, src, **kwds)\u001b[0m\n\u001b[0;32m   1706\u001b[0m         \u001b[0mkwds\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'usecols'\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0musecols\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1707\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1708\u001b[1;33m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_reader\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mparsers\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTextReader\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msrc\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m   1709\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m   1710\u001b[0m         \u001b[0mpassed_names\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnames\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32mpandas\\_libs\\parsers.pyx\u001b[0m in \u001b[0;36mpandas._libs.parsers.TextReader.__cinit__\u001b[1;34m()\u001b[0m\n",
      "\u001b[1;32mpandas\\_libs\\parsers.pyx\u001b[0m in \u001b[0;36mpandas._libs.parsers.TextReader._setup_parser_source\u001b[1;34m()\u001b[0m\n",
      "\u001b[1;31mFileNotFoundError\u001b[0m: File b'ex1data2.txt' does not exist"
     ]
    }
   ],
   "source": [
    "raw_data = pd.read_csv('ex1data2.txt', names=['square', 'bedrooms', 'price'])\n",
    "raw_data.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "collapsed": true,
    "id": "7WBXHMXzU8e6"
   },
   "source": [
    "# 标准化数据\n",
    "最简单的方法是令：\n",
    "\n",
    " \n",
    "\n",
    "其中  是平均值，sn 是标准差。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "sFLN1gSfU8e7"
   },
   "outputs": [],
   "source": [
    "def normalize_feature(df):\n",
    "#     \"\"\"Applies function along input axis(default 0) of DataFrame.\"\"\"\n",
    "    return df.apply(lambda column: (column - column.mean()) / column.std())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "SL2V8gRmU8e-"
   },
   "outputs": [],
   "source": [
    "data = normalize_feature(raw_data)\n",
    "data.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "pjP2SsV3U8fE"
   },
   "source": [
    "# 2. 多变量批量梯度下降 -  Multi-var batch gradient decent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "XHTA9KcXU8fE"
   },
   "outputs": [],
   "source": [
    "X = get_X(data)\n",
    "print(X.shape, type(X))\n",
    "\n",
    "y = get_y(data)\n",
    "print(y.shape, type(y)) #看下数据的维度和类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "PUHGSR5jU8fI"
   },
   "outputs": [],
   "source": [
    "alpha = 0.01 #学习率\n",
    "theta = np.zeros(X.shape[1]) #X.shape[1]：特征数n\n",
    "epoch = 500  #迭代次数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "NbC5-6NfU8fL"
   },
   "outputs": [],
   "source": [
    "final_theta, cost_data = batch_gradient_decent(theta, X, y, epoch, alpha=alpha)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "DTvLgpImU8fN"
   },
   "outputs": [],
   "source": [
    "sns.tsplot(time=np.arange(len(cost_data)), data = cost_data)\n",
    "plt.xlabel('epoch', fontsize=18)\n",
    "plt.ylabel('cost', fontsize=18)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "XIAeC3aWU8fQ"
   },
   "outputs": [],
   "source": [
    "final_theta"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "xhv7H1OSTZJs"
   },
   "source": [
    "Scikit-learn 的预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "Dx3gtarBk2Os",
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "from mpl_toolkits.mplot3d import Axes3D\n",
    "from sklearn import linear_model\n",
    "\n",
    "model = linear_model.LinearRegression()\n",
    "model.fit(X, y)\n",
    "\n",
    "f = model.predict(X).flatten()\n",
    "\n",
    "fig = plt.figure()\n",
    "ax = fig.add_subplot(111, projection='3d')\n",
    "ax.plot(X[:,1], X[:,2], f, 'r', label='Prediction')\n",
    "ax.scatter(X[:,1], X[:,2], y, label='Traning Data')\n",
    "ax.legend(loc=2)\n",
    "ax.set_xlabel('square')\n",
    "ax.set_ylabel('bedrooms')\n",
    "ax.set_zlabel('price')\n",
    "ax.set_title('square & bedrooms vs. price')\n",
    "#ax.view_init(30, 10)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "IRrnttEHU8fS"
   },
   "source": [
    "# 3. 学习率 - Learning rate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "w9U-3YXMU8fT"
   },
   "outputs": [],
   "source": [
    "base = np.logspace(-1, -5, num=4)\n",
    "candidate = np.sort(np.concatenate((base, base*3)))\n",
    "print(candidate)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "ePELIHY-U8fV"
   },
   "outputs": [],
   "source": [
    "epoch=50\n",
    "\n",
    "fig, ax = plt.subplots(figsize=(8, 8))\n",
    "\n",
    "for alpha in candidate:\n",
    "    _, cost_data = batch_gradient_decent(theta, X, y, epoch, alpha=alpha)\n",
    "    ax.plot(np.arange(epoch+1), cost_data, label=alpha)\n",
    "\n",
    "ax.set_xlabel('epoch', fontsize=12)\n",
    "ax.set_ylabel('cost', fontsize=12)\n",
    "ax.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)\n",
    "ax.set_title('learning rate', fontsize=12)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "SwpPCazZg3Ik"
   },
   "source": [
    "可以看到最合适的learning rate是0.3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "6-HlM4onU8fX"
   },
   "source": [
    "# 4. 正规方程 - Normal equation\n",
    "正规方程是通过求解下面的方程来找出使得代价函数最小的参数的：$\\frac{\\partial }{\\partial {{\\theta }_{j}}}J\\left( {{\\theta }_{j}} \\right)=0$ 。\n",
    " 假设我们的训练集特征矩阵为 X（包含了${{x}_{0}}=1$）并且我们的训练集结果为向量 y，则利用正规方程解出向量 $\\theta ={{\\left( {{X}^{T}}X \\right)}^{-1}}{{X}^{T}}y$ 。\n",
    "上标T代表矩阵转置，上标-1 代表矩阵的逆。设矩阵$A={{X}^{T}}X$，则：${{\\left( {{X}^{T}}X \\right)}^{-1}}={{A}^{-1}}$\n",
    "\n",
    "梯度下降与正规方程的比较：\n",
    "\n",
    "梯度下降：需要选择学习率α，需要多次迭代，当特征数量n大时也能较好适用，适用于各种类型的模型\t\n",
    "\n",
    "正规方程：不需要选择学习率α，一次计算得出，需要计算${{\\left( {{X}^{T}}X \\right)}^{-1}}$，如果特征数量n较大则运算代价大，因为矩阵逆的计算时间复杂度为O(n3)，通常来说当n小于10000 时还是可以接受的，只适用于线性模型，不适合逻辑回归模型等其他模型\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "BGjQLe7jU8fY"
   },
   "outputs": [],
   "source": [
    "# 正规方程\n",
    "def normalEqn(X, y):\n",
    "    theta = np.linalg.inv(X.T@X)@X.T@y#X.T@X等价于X.T.dot(X)\n",
    "    return theta"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "3JB8AH_iU8fa"
   },
   "outputs": [],
   "source": [
    "final_theta2=normalEqn(X, y)#感觉和批量梯度下降的theta的值有点差距\n",
    "final_theta2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "YfBLlOZnY6Qi"
   },
   "outputs": [],
   "source": [
    "f = final_theta2[0] + final_theta2[1] * X[:,1] + final_theta2[2] * X[:,2]\n",
    "\n",
    "fig = plt.figure()\n",
    "ax = fig.add_subplot(111, projection='3d')\n",
    "ax.plot(X[:,1], X[:,2], f, 'r', label='Prediction')\n",
    "ax.scatter(X[:,1], X[:,2], y, label='Traning Data')\n",
    "ax.legend(loc=2)\n",
    "ax.set_xlabel('square')\n",
    "ax.set_ylabel('bedrooms')\n",
    "ax.set_zlabel('price')\n",
    "ax.set_title('square & bedrooms vs. price')\n",
    "#ax.view_init(30, 10)\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "1.linear_regreesion_v1.ipynb",
   "provenance": [],
   "toc_visible": true,
   "version": "0.3.2"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
